//#pragma once
#include<iostream>
#include<unistd.h>
#include<assert.h>
#include<string>
#include<cstring>
#include<cstdio>
#include<sys/types.h>
#include<sys/wait.h>

using namespace std;

//演示以fork父子进程的方式创建匿名管道
int main()
{
    //step1：创建一个管道
    int pipefd[2] = {0};//文件描述符数组，用于接受pipe读端、写端
    int ret = pipe(pipefd);
    assert(ret != -1);//用于检测是否成功创建管道
    (void)ret;//assert只在debug模式下有效，为了避免release模式下ret变量未被使用而报警设置。

    
    //验证:pipefd[2]具体含义
    #ifdef DEBUG
    cout << "pipefd[0]" << pipefd[0] << endl;
    cout << "pipefd[1]" << pipefd[1] << endl;
    cout<<endl;
    #endif

    //step2:创建子进程，对父子进程构建单向通信的信道
    pid_t id = fork();
    assert(id != -1);//fork失败
    if(0 == id)//子进程：此处设子进程读取
    {
        close(pipefd[1]);//对子进程，保留读端，关闭写端

        //……相关读取操作
        char re_buffer[1024*8]={0};//子进程缓冲区：用于接收读端读取到的数据
        while(true)
        {
            
            //从管道中读取数据存储入缓冲区
            ssize_t re = read(pipefd[0], re_buffer, sizeof(re_buffer)-1);
            if(re > 0)
            {
                re_buffer[re]= 0;
                cout << "【childpid-" << getpid() << ", get a message 】：" << re_buffer << endl;
            }
            else if(re == 0)//end of file
            {
                cout << "child: end of file, quit." << endl;
                break;//退出循环
            }
        }

        exit(0);//终止子进程
    }
    //父进程：此处设父进程写入
    close(pipefd[0]);//对父进程，保留写端，关闭读端

    //……相关写入操作
    char wr_buffer[1024*8]={0};//写端缓冲区，用于存储发送的数据
    string message = "父进程写入数据";//提示文字1
    int count=0;//提示文字2
    while(true)
    {
        //向wr_buffer中写入相关信息，并将其显示
        snprintf(wr_buffer,sizeof(wr_buffer),"fatherid-%d, %s, 第%d写入.",getpid(),message.c_str(),1+count++);
        //将写端缓冲区数据传入管道
        write(pipefd[1],wr_buffer,strlen(wr_buffer));
        //结束写端
        sleep(1);
        if(10 == count)
        {
            cout<<"father quit!\n"<<endl;
            break;
        }
    }

    //step3：执行完毕
    close(pipefd[1]);
    pid_t ret2 = waitpid(id, nullptr, 0);
    printf("wait:%d, childpid:%d, count:%d\n",ret2,id,count);
    assert(ret2 > 0);
    (void)ret2;

    return 0;
}
